SpringDataJpa的使用 您所在的位置:网站首页 {articleimage} SpringDataJpa的使用

SpringDataJpa的使用

2024-01-11 20:22| 来源: 网络整理| 查看: 265

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

SpringDataJpa的使用 -- 条件查询、排序查询、分页查询

本文以 Article.java 为数据存放类,操作接口为 ArticleRepository.java

@Data lombok 的注解,用来生成 Getter、Setter、toString、hashCode 方法,当添加该注解的同时在添加 相应方法(如 toString())时,添加的方法不会被覆盖。

@NoArgsConstructor lombok 的注解,用来生成 无参构造函数。

@AllArgsConstructor lombok 的注解,用来生成 全参构造函数。

@JsonIgnore 用来破坏实体类序列化时,产生的无限递归循环。

在本次的测试中,还需要 重写 Author.java 的 toString 方法,目的是这两个类中必须有一方的 toString 方法没有外键属性,可以双方都没有。

Author.java

/** * 作者 类 * * @author LJM */ @Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name = "AUTHOR") public class Author { /** * 作者 id */ @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "author_id", nullable = false) private Long authorId; /** * 作者 姓名 */ @Column(name = "author_Name", nullable = false) private String authorName; /** * 作者 简介 */ @Column(name = "author_referral", nullable = false) private String authorReferral; /** * 一对多 * 一方 * (被)维护方 * * 文章列表 */ @JsonIgnore @OneToMany(mappedBy = "author", fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.REMOVE}) private List articleList; @Override public String toString() { return "Author{" + "authorId=" + authorId + ", authorName='" + authorName + '\'' + ", authorReferral='" + authorReferral + '\'' + '}'; } }

Article.java

/** * 文章 类 * * @author LJM */ @Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name = "ARTICLE") public class Article { /** * 文章 id */ @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "article_id", nullable = false) private Long articleId; /** * 文章 标题 */ @Column(name = "article_title", nullable = false) private String articleTitle; /** * 文章 内容 */ @Column(name = "article_content", nullable = false) private String articleContent; /** * 文章 类型 */ @Column(name = "article_type", nullable = false) private String articleType; /** * 文章 阅读量 */ @Column(name = "article_read_number", nullable = false) private Integer articleReadNumber; /** * 文章 点赞数 */ @Column(name = "article_likes_number", nullable = false) private Integer articleLikesNumber; /** * 多对一 * 多方 * 作者外键 * 维护方 */ @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "article_author_id", nullable = false) private Author author; }

ArticleRepository.java 这只是最基础的内容,会后续添加 接口或方法 来增加功能。

public interface ArticleRepository extends JpaRepository { } 排序查询 法 一

使用 JpaRepository 的 List findAll(Sort sort) 方法,无需添加新的 方法或接口。

Sort.by(String) 方法的参数是 字符串数组,可以添加一到多个类属性名来排序。

ascending 方法表示升序排序(默认就是),写法:Sort.by(String).ascending()。

descending 方法表示降序排序,写法:Sort.by(String).descending()。

根据多个类属性来排序时,是在不破坏前一个的排序结果的基础上对后一个进行排序,以此类推。

@Test public void test1(){ List articleList=articleRepository.findAll(Sort.by("articleType").ascending()); System.out.println("====== 升序(类型) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); List articleList1=articleRepository.findAll(Sort.by("articleType","articleReadNumber").ascending()); System.out.println("====== 升序(类型)(阅读量) ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); } 如果 输入的类属性不存在就会报错,故需要:检验输入的类属性是否存在 @Test public void test2(){ List articleList=articleRepository.findAll(Sort.by("articleType1").ascending()); System.out.println("====== 升序(类型) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); } org.springframework.data.mapping.PropertyReferenceException: No property 'articleType1' found for type 'Article'! Did you mean ''articleType''? 能不能设置按第一个属性升序,再按第二个属性降序呢?答案是:当然。

by() 是静态方法,不支持变量调用,每一个 by() 后只能添加一个 排序方法。 但是,Sort 有一个 and(Sort) 方法,用来将两个 Sort 合并,该方法由变量调用,理论上可以无限叠加。

@Test public void test3(){ List articleList=articleRepository.findAll(Sort.by("articleType","articleReadNumber").ascending()); System.out.println("====== 升序(类型)(阅读量) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); Sort sort=Sort.by("articleType").ascending(); sort=sort.and(Sort.by("articleReadNumber").descending()); List articleList1=articleRepository.findAll(sort); System.out.println("====== 类型升序、再阅读量降序 ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); } 分页查询 法 一

使用 PagingAndSortingRepository 的 Page findAll(Pageable pageable) 方法,JpaRepository 继承了 PagingAndSortingRepository 接口,无需添加新的 方法或接口。

Page 几个常用的属性:

content 数组 ,存放 List 的形式的数据。 pageable 类,与上面的方法的参数一致,存放了数据的总数、当前页数、当前排序属性 等等。

用 PageRequest.of([页码],[页大小]) 创建 Pageable 变量,然后填入 Page findAll(Pageable) 方法即可。

@Test public void test4(){ Pageable pageable=PageRequest.of(0,5); Page articleList=articleRepository.findAll(pageable); System.out.println("====== 分页结果 0,5 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); Pageable pageable1=PageRequest.of(0,30); Page articleList1=articleRepository.findAll(pageable1); System.out.println("====== 分页结果 0,30 ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); }

注意:PageRequest.of(0, 5) 表示 第一页,每页5条;PageRequest.of(1, 5) 表示 第二页,每页5条。

当页数大于数据条数时,如果是第一页,不报错,查询全部;如果不是第一页,那么无法执行,即:当前页码的数据必须大于等于一条,才能成功执行。 我之前测试时,是报错的,现在又可以了。

@Test public void test5(){ Pageable pageable=PageRequest.of(1,5); Page articleList=articleRepository.findAll(pageable); System.out.println("====== 分页结果 0,5 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); Pageable pageable2=PageRequest.of(1,10); Page articleList2=articleRepository.findAll(pageable2); System.out.println("====== 分页结果 0,30 ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); } 条件查询 法 一 使用 JpaRepository 提供的,通过使用关键字来实现的条件查询。功能丰富。

Spring Data JPA 查询方法支持的关键字

如:根据文章类型查询、根据 文章 类型 和 部分文章内容 查询 等等。 /** * 文章 操作 接口 * * @author l'j'm */ public interface ArticleRepository extends JpaRepository { /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findByArticleType(String articleType); /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findAllByArticleType(String articleType); /** * 根据 文章 类型 和 部分文章内容 查询 * * @param articleType 文章 类型 * @param articleContent 文章内容 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent); }

Jpa 支持的关键字中,已经描述的很详细了,不再重复描述。

标准的写法是以 findBy 开头的,当然 findAllBy 开头的结果是一样,但不建议。

@Test public void aVoid1(){ List articleList=articleRepository.findByArticleType("后端"); List articleList1=articleRepository.findAllByArticleType("后端"); System.out.println("====== 默认 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 默认(All) ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); } @Test public void aVoid2(){ List articleList=articleRepository.findByArticleType("后端"); List articleList2=articleRepository .findByArticleType("后端",Sort.by("articleReadNumber").ascending()); List articleList3=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%"); System.out.println("====== 默认 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 查询,升序(阅读量) ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======"); articleList3.stream().map(Objects::toString).forEach(System.out::println); } 组合 是指,三种不同的查询分类 两两结合 或 三个成组 地使用,可以适应比较复杂的查询。 条件 + 排序 法 一

在 根据关键字实现的 接口方法中添加参数 Sort 就可以添加排序条件。

注意:方法名不能改,即 想要添加 排序,只需添加添加参数 Sort,不能改方法名。

为什么可以这样写呢?

因为,添加关键字来实现 条件查询,实现时是在内部解析 方法名,然后构建 SQL 语句,最后剩下 findAll(Sort) ,而该方法是有对应的解析方法的。

/** * 文章 操作 接口 * * @author l'j'm */ public interface ArticleRepository extends JpaRepository { /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findByArticleType(String articleType); /** * 根据 文章 类型 查询 并排序 * * @param articleType 文章 类型 * @param sort 排序条件 * * @return list */ List findByArticleType(String articleType, Sort sort); /** * 根据 文章 类型 和 部分文章内容 查询 * * @param articleType 文章 类型 * @param articleContent 文章内容 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent); /** * 根据 文章 类型 和 部分文章内容 查询 并排序 * * @param articleType 文章 类型 * @param articleContent 文章内容 * @param sort 排序条件 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Sort sort); } 测试 @Test public void aVoid2(){ List articleList=articleRepository.findByArticleType("后端"); List articleList2=articleRepository .findByArticleType("后端",Sort.by("articleReadNumber").ascending()); List articleList3=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%"); List articleList4=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%",Sort.by("articleReadNumber").ascending()); System.out.println("====== 默认 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 查询,升序(阅读量) ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======"); articleList3.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询,升序(阅读量) ======"); articleList4.stream().map(Objects::toString).forEach(System.out::println); } 条件 + 分页 法 一

在 根据关键字实现的 接口方法中添加参数 Pageable 就可以添加 分页条件。

注意:方法名不能改,即 想要添加 分页,只需添加添加参数 Pageable,不能改方法名。

为什么可以这样写呢?

因为,添加关键字来实现 条件查询时,实现是在内部解析 方法名,然后构建 SQL 语句,最后剩下 findAll(Pageable) ,而该方法是有对应的解析方法的。

/** * 文章 操作 接口 * * @author l'j'm */ public interface ArticleRepository extends JpaRepository { /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findByArticleType(String articleType); /** * 根据 文章 类型 查询 并 分页 * * @param articleType 文章 类型 * @param pageable 分页条件 * * @return list */ List findByArticleType(String articleType, Pageable pageable); /** * 根据 文章 类型 和 部分文章内容 查询 * * @param articleType 文章 类型 * @param articleContent 文章内容 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent); /** * 根据 文章 类型 和 部分文章内容 查询 并 分页 * * @param articleType 文章 类型 * @param articleContent 文章内容 * @param pageable 分页条件 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Pageable pageable); } 测试 @Test public void aVoid3(){ List articleList=articleRepository.findByArticleType("后端"); List articleList2=articleRepository .findByArticleType("后端",PageRequest.of(0,2)); List articleList3=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%"); List articleList4=articleRepository .findByArticleTypeAndArticleContentLike("后端","%好%",PageRequest.of(1,1)); System.out.println("====== 默认 ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 查询,分页(0,2) ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询 ======"); articleList3.stream().map(Objects::toString).forEach(System.out::println); System.out.println("====== 根据 文章 类型 和 部分文章内容 查询,分页(1,1) ======"); articleList4.stream().map(Objects::toString).forEach(System.out::println); } 分页 + 排序 法 一

Pageable 类中有参数 Sort,只需 将配置好的 Sort 传入 Pageable 中即可

其他的 使用方法,与前文无异。

@Test public void void1(){ Sort sort=Sort.by("articleType").ascending(); List articleList=articleRepository.findAll(sort); System.out.println("====== 升序(类型) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); Pageable pageable=PageRequest.of(1,5); Page articleList1=articleRepository.findAll(pageable); System.out.println("====== 分页结果 0,5 ======"); articleList1.stream().map(Objects::toString).forEach(System.out::println); // Pageable pageable1 = PageRequest.of(1, 5).withSort(sort); Pageable pageable1=PageRequest.of(1,5,sort); Page articleList2=articleRepository.findAll(pageable1); System.out.println("====== 分页结果 0,5 ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); } 条件 + 分页 + 排序

注意 踩坑:没有 findBy...And...(String..., Pageable, Sort) 这种写法的。

原因:没有 findAll(Pageable, Sort) 这个基方法。

findByArticleType(String, Pageable) 和 findByArticleType(String, Sort) 可以执行,是因为有 findAll(Pageable),findAll(Sort) 这两个基方法。

法 一

看了前文你应该猜到了,没错,就是 用关键字实现条件查询,再添加 带有排序的分页参数实现。

写法 是:findBy...And...(String..., Pageable),直接套用 条件 + 分页 方法即可 /** * 文章 操作 接口 * * @author l'j'm */ public interface ArticleRepository extends JpaRepository { /** * 根据 文章 类型 查询 * * @param articleType 文章 类型 * * @return list */ List findByArticleType(String articleType); /** * 根据 文章 类型 查询 并 分页 * * @param articleType 文章 类型 * @param pageable 分页条件 * * @return list */ List findByArticleType(String articleType, Pageable pageable); /** * 根据 文章 类型 和 部分文章内容 查询 * * @param articleType 文章 类型 * @param articleContent 文章内容 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent); /** * 根据 文章 类型 和 部分文章内容 查询 并 分页 * * @param articleType 文章 类型 * @param articleContent 文章内容 * @param pageable 分页条件 * * @return list */ List findByArticleTypeAndArticleContentLike(String articleType, String articleContent, Pageable pageable); } 测试 @Test public void void2(){ Sort sort=Sort.by("articleReadNumber").descending(); Pageable pageable=PageRequest.of(0,5); // Pageable pageable1 = PageRequest.of(0, 5).withSort(sort); Pageable pageable1=PageRequest.of(0,5,sort); List articleList=articleRepository.findByArticleType("后端",pageable); System.out.println("====== 后端,分页结果 (0,5) ======"); articleList.stream().map(Objects::toString).forEach(System.out::println); List articleList2=articleRepository.findByArticleType("后端",pageable1); System.out.println("====== 后端,分页结果 (0,5),排序 ======"); articleList2.stream().map(Objects::toString).forEach(System.out::println); }

关于 分组查询 和 统计查询 下篇更新。

(二发)如果对你有帮助,点赞可好!!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有